#pragma once
#include <string>
#include <map>
#include <vector>
#include <set>
#include <iostream>
#include <boost/tokenizer.hpp>
#include <boost/smart_ptr.hpp>

namespace html { namespace dom
{
  using namespace std;
  using namespace boost;

  struct node;
  struct selector;
  struct text_after_start_tag_accessor;
  struct tag_accessor;
  struct id_accessor;
  struct class_accessor;
  struct text_after_end_tag_accessor;

  /// @brief array of node
  typedef vector<node> nodes_data;
  /// @brief array of nodes in kind of a shared pointer with several access methods
  struct nodes {
    /// @brief creates a new nodes container
    nodes() : data_(new nodes_data) {}
    nodes( const nodes& _nodes) : data_(_nodes.data_) {}
    nodes( const node& _node);
    /// @brief add a node to this container
    void add( const nodes& _nodes );
    /// @brief recursively search for one node by an unique id attribute value
    /// in all contained nodes and descendants
    /// @return the found node
    /// @throw exception if node wasn't found
    node operator[] (int n);
    /// @brief find one or more contained nodes or descendants that match a CSS-like selector
    /// @return found nodes
    nodes operator() (const selector& _selector);
    /// @brief access all tag names of all contained nodes (excluding descendants)
    /// @return accessor that provides access to all tag names
    tag_accessor tag();
    /// @brief access all ids of all contained nodes (excluding descendants)
    /// @return accessor that provides access to all ids
    id_accessor id();
    /// @brief access all class sets of all contained nodes (excluding descendants)
    /// @return accessor that provides access to all class sets
    class_accessor classes();
    /// @brief const iterator for contained nodes
    typedef nodes_data::const_iterator const_iterator;
    /// @brief returns const iterator to the first node
    const_iterator begin() const { return data_->begin(); }
    /// @brief returns const iterator that points behind the last node
    const_iterator end() const { return data_->end(); }
    /// @brief iterator for contained nodes
    typedef nodes_data::iterator iterator;
    /// @brief returns iterator to the first node
    iterator begin() { return data_->begin(); }
    /// @brief return iterator that points behind the last node
    iterator end() { return data_->end(); }
    /// @brief append node to this container
    void push_back( const node& _node ) { data_->push_back(_node); }
    const nodes& operator+=( const node& _node ) { push_back(_node); return *this; }
    iterator insert( iterator _loc, const node& _node ) { data_->insert(_loc,_node); }
    /// @brief return a reference to the last node
    node& back() { return data_->back(); }
    /// @brief return the number of contained nodes  
    size_t size() { return data_->size(); }
  private:
    /// @brief typedef of a shared pointer to a nodes_data instance
    typedef shared_ptr<nodes_data> nodes_ptr;
    /// @brief shared pointer to nodes_data instance
    nodes_ptr data_;
  };
  inline nodes operator,(nodes& _nodes, const node& _node);
} }

